{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 2, Topic 1, Lab B: Power Analysis for Password Bypass (MAIN)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *This tutorial will introduce you to breaking devices by determining when a device is performing certain operations. Our target device will be performing a simple password check, and we will demonstrate how to perform a basic power analysis.*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* How power can be used to determine timing information.\n",
    "* Plotting multiple iterations while varying input data to find interesting locations.\n",
    "* Using difference of waveforms to find interesting locations.\n",
    "* Performing power captures with ChipWhisperer hardware (hardware only)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prerequisites"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hold up! Before you continue, check you've done the following tutorials:\n",
    "\n",
    "* ☑ Jupyter Notebook Intro (you should be OK with plotting & running blocks).\n",
    "* ☑ SCA101 Intro (you should have an idea of how to get hardware-specific versions running)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Power Trace Gathering"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At this point you've got to insert code to perform the power trace capture. There are two options here:\n",
    "* Capture from physical device.\n",
    "* Read from a file.\n",
    "\n",
    "You get to choose your adventure - see the two notebooks with the same name of this, but called `(SIMULATED)` or `(HARDWARE)` to continue. Inside those notebooks you should get some code to copy into the following section, which will define the capture function.\n",
    "\n",
    "Be sure you get the `\"✔️ OK to continue!\"` print once you run the next cell, otherwise things will fail later on!\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#\n",
    "# DEFINE THE cap_pass_trace() function - either using a hardware connection or the file read-out.\n",
    "#\n",
    "raise NotImplementedError(\"Add your code here, and delete this.\")\n",
    "\n",
    "trace_test = cap_pass_trace(\"h\\n\")\n",
    "\n",
    "#Basic sanity check\n",
    "assert(len(trace_test) == 3000)\n",
    "print(\"✔️ OK to continue!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exploration"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So what can we do with this? While first off - I'm going to cheat, and tell you that we have a preset password that starts with `h`, and it's 5 characters long. But that's the only hint so far - what can you do? While first off, let's try plotting a comparison of `h` to something else.\n",
    "\n",
    "If you need a reminder of how to do a plot - see the matplotlib section of the **Jupyter Introduction** notebook.\n",
    "\n",
    "The following cell shows you how to capture one power trace with `h` sent as a password. From there:\n",
    "\n",
    "1. Try adding the plotting code and see what it looks like.\n",
    "2. Send different passwords to the device. We're only going to look at the difference between a password starting with `h` and something else right now.\n",
    "3. Plot the different waveforms."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Example - capture 'h' - end with newline '\\n' as serial protocol expects that\n",
    "trace_h = cap_pass_trace(\"h\\n\")\n",
    "\n",
    "print(trace_h)\n",
    "\n",
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "raise NotImplementedError(\"Add your code here, and delete this.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For reference, the output should look something like this:\n",
    "<img src=\"img/spa_password_h_vs_0_overview.png\" alt=\"SPA of Power Analysis\" width=\"450\"/>\n",
    "\n",
    "If you are using the `%matplotlib notebook` magic, you can zoom in at the start. What you want to notice is there is two code paths taken, depending on a correct or incorrect path. Here for example is a correct & incorrect character processed:\n",
    "<img src=\"img/spa_password_h_vs_0_zoomed.png\" alt=\"SPA of Power Analysis\" width=\"450\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "OK interesting -- what's next? Let's plot every possible password character we could send.\n",
    "\n",
    "Our password implementation only recognizes characters in the list `abcdefghijklmnopqrstuvwxyz0123456789`, so we're going to limit it to those valid characters for now.\n",
    "\n",
    "Write some code in the following block that implements the following algorithm:\n",
    "\n",
    "    for CHARACTER in LIST_OF_VALID_CHARACTERS:\n",
    "        trace = cap_pass_trace(CHARACTER + \"\\n\")\n",
    "        plot(trace)\n",
    "        \n",
    "The above isn't quite valid code - so massage it into place! You also may notice the traces are way too long - you might want to make a more narrow plot that only does the first say 500 samples of the power trace.\n",
    "\n",
    "---\n",
    "📝**Plotting Note**\n",
    "\n",
    "If using `matplotlib` for plotting, you might need to add a `plt.figure()` at the start to make a new figure. Otherwise you might find your plot ends up in the figure above! If you don't see the plots, sometimes a `plt.show()` is needed at the end.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "raise NotImplementedError(\"Add your code here, and delete this.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The end result should be if you zoom in, you'll see there is a location where a single \"outlier\" trace doesn't follow the path of all the other traces. That is great news, since it means we learn something about the system from power analysis.\n",
    "\n",
    "<img src=\"img/spa_password_list_char1.png\" alt=\"SPA of Power Analysis against all inputs\" width=\"450\"/>\n",
    "\n",
    "Using your loop - you can also try modifying the analysis to capture a correct \"first\" character, and then every other wrong second character. Do you see a difference you might be able to detect?\n",
    "\n",
    "The pseudo-code would look something like this:\n",
    "\n",
    "    for CHARACTER in LIST_OF_VALID_CHARACTERS:\n",
    "        trace = cap_pass_trace(\"h\" + CHARACTER + \"\\n\")\n",
    "        plot(trace)\n",
    "\n",
    "Give that a shot in your earlier code-block, and then let's try and automate this attack to understand the data a little better."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Automating an Attack against One Character"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To start with - we're going to automate an attack against a **single** character of the password. Since we don't know the password (let's assume), we'll use a strategy of comparing all possible inputs together.\n",
    "\n",
    "An easy way to do this might be to use something that we know can't be part of the valid password. As long as it's processed the same way, this will work just fine. So for now, let's use a password as `0x00` (i.e., a null byte). We can compare the null byte to processing something else:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ref_trace = cap_pass_trace(\"\\x00\\n\")[0:1000]\n",
    "fig = cw.plot(ref_trace)\n",
    "other_trace = cap_pass_trace(\"c\\n\")[0:1000]\n",
    "fig *= cw.plot(other_trace)\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This will plot a trace with an input of \"\\x00\" - a null password! This is an invalid character, and seems to be processed as any other invalid password.\n",
    "\n",
    "Let's make this a little more obvious, and plot the difference between a known reference & every other capture. You need to write some code that does something like this:\n",
    "\n",
    "```python\n",
    "ref_trace = cap_pass_trace( \"\\x00\\n\")\n",
    "\n",
    "for CHARACTER in LIST_OF_VALID_CHARACTERS:\n",
    "    trace = cap_pass_trace(CHARACTER + \"\\n\")\n",
    "    plot(trace - ref_trace)\n",
    "```\n",
    "\n",
    "Again, you may need to modify this a little bit such as adding code to make a new `figure()`. Also notice in the above example how I reduced the number of samples.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "raise NotImplementedError(\"Add your code here, and delete this.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "OK great - hopefully you now see one major \"difference\". It should look something like this:\n",
    "    \n",
    "<img src=\"img/spa_password_diffexample.png\" alt=\"SPA with Difference\" width=\"450\"/>\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What do do now? Let's make this thing automatically detect such a large difference. Some handy stuff to try out is the `np.sum()` and `np.abs()` function.\n",
    "\n",
    "The first one will get absolute values:\n",
    "\n",
    "```python\n",
    "import numpy as np\n",
    "np.abs([-1, -3, 1, -5, 6])\n",
    "\n",
    "    Out[]: array([1, 3, 1, 5, 6])\n",
    "```\n",
    "\n",
    "The second one will add up all the numbers.\n",
    "\n",
    "```python\n",
    "import numpy as np    \n",
    "np.sum([-1, -3, 1, -5, 6])\n",
    "\n",
    "    Out[]: -2\n",
    "```\n",
    "\n",
    "Using just `np.sum()` means positive and negative differences will cancel each other out - so it's better to do something like `np.sum(np.abs(DIFF))` to get a good number indicating how \"close\" the match was.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "np.abs([-1, -3, 1, -5, 6])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "np.sum([-1, -3, 1, -5, 6])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.sum(np.abs(<COPY DATA HERE>))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Taking your above loop, modify it to print an indicator of how closely this matches your trace. Something like the following should work:\n",
    "\n",
    "    ref_trace = cap_pass_trace( \"\\x00\\n\")\n",
    "\n",
    "    for CHARACTER in LIST_OF_VALID_CHARACTERS:\n",
    "        trace = cap_pass_trace(CHARACTER + \"\\n\")\n",
    "        diff = SUM(ABS(trace - ref_trace))\n",
    "\n",
    "        print(\"{:1} diff = {:2}\".format(CHARACTER, diff))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "raise NotImplementedError(\"Add your code here, and delete this.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now the easy part - modify your above code to automatically print the correct password character. This should be done with a comparison of the `diff` variable - based on the printed characters, you should see one that is 'higher' than the others. Set a threshold somewhere reasonable (say I might use `25.0` based on one run)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Running a Full Attack"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally - let's finish this off. Rather than attacking a single character, we need to attack each character in sequence.\n",
    "\n",
    "If you go back to the plotting of differences, you can try using the correct first character & wrong second character. The basic idea is exactly the same as before, but now we loop through 5 times, and just build up the password based on brute-forcing each character.\n",
    "\n",
    "Take a look at the following for the basic pseudo-code:\n",
    "\n",
    "    guessed_pw = \"\" #Store guessed password so far\n",
    "    \n",
    "    do a loop 5 times (max password size):\n",
    "        \n",
    "        ref_trace = capture power trace(guessed_pw + \"\\x00\\n\")\n",
    "        \n",
    "        for CHARACTER in LIST_OF_VALID_CHARACTERS:\n",
    "            trace = capture power trace (guessed_pw + CHARACTER + newline)\n",
    "            diff = SUM(ABS(trace - ref_trace))\n",
    "            \n",
    "            if diff > THRESHOLD:\n",
    "                \n",
    "                guessed_pwd += c\n",
    "                print(guessed_pw)\n",
    "                \n",
    "                break\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "raise NotImplementedError(\"Add your code here, and delete this.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should get an output that looks like this:\n",
    "\n",
    "    h\n",
    "    h0\n",
    "    h0p\n",
    "    h0px\n",
    "    h0px3\n",
    "\n",
    "If so - 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 Congrats - you did it!!!!\n",
    "\n",
    "If not - check some troubleshooting hints below. If you get really stuck, check the `SOLN` version (there is one for both with hardware and simulated)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## Troubleshooting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some common problems you might run into - first, if you get an output which keeps guessing the first character:\n",
    "\n",
    "### Always get 'h'\n",
    "\n",
    "    h\n",
    "    hh\n",
    "    hhh\n",
    "    hhhh\n",
    "    hhhhh\n",
    "\n",
    "Check that when you run the `cap_pass_trace` inside the loop (checking the guessed password), are you updating the prefix of the password? For example, the old version of the code (guessing a single character) looked like this:\n",
    "\n",
    "    trace = cap_pass_trace(c + \"\\n\")\n",
    "\n",
    "But that is always sending our first character only! So we need to send the \"known good password so far\". In the example code something like this:\n",
    "   \n",
    "    trace = cap_pass_trace(guessed_pw + c + \"\\n\")\n",
    "\n",
    "Where `guessed_pw` progressively grows with the known good start of the password.\n",
    "\n",
    "### Always get 'a'\n",
    "\n",
    "This looks like it's always matching the first character:\n",
    "\n",
    "    h\n",
    "    ha\n",
    "    haa\n",
    "    haaa\n",
    "    haaaa\n",
    "\n",
    "Check that you update the `ref_trace` - if you re-use the original reference trace, you won't be looking at a reference where the first N characters are good, and the remaining characters are bad. An easy way to do this is again using the `guessed_pw` variable and appending a null + newline:\n",
    "\n",
    "    trace = cap_pass_trace(guessed_pw + \"\\x00\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<small>NO-FUN DISCLAIMER: This material is Copyright (C) NewAE Technology Inc., 2015-2020. ChipWhisperer is a trademark of NewAE Technology Inc., claimed in all jurisdictions, and registered in at least the United States of America, European Union, and Peoples Republic of China.\n",
    "\n",
    "Tutorials derived from our open-source work must be released under the associated open-source license, and notice of the source must be *clearly displayed*. Only original copyright holders may license or authorize other distribution - while NewAE Technology Inc. holds the copyright for many tutorials, the github repository includes community contributions which we cannot license under special terms and **must** be maintained as an open-source release. Please contact us for special permissions (where possible).\n",
    "\n",
    "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</small>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
